#if !defined(AFX_GETHWINFO_H__3ABD86B7_D2D2_43EB_B89D_582D73A89BF8__INCLUDED_)
#define AFX_GETHWINFO_H__3ABD86B7_D2D2_43EB_B89D_582D73A89BF8__INCLUDED_

#if _MSC_VER > 1000
    #pragma once
#endif // _MSC_VER > 1000
#include <Windows.h>
#include <winioctl.h>

#define NAMESPACE_HARDWARE_BEGIN    namespace HardwareInfo {
#define NAMESPACE_HARDWARE_END      }

NAMESPACE_HARDWARE_BEGIN
#define  IDENTIFY_BUFFER_SIZE       512
#define  DFP_GET_VERSION            0x00074080
#define  DFP_RECEIVE_DRIVE_DATA     0x0007c088
#define  IDE_ATAPI_IDENTIFY         0xA1  //  Returns ID sector for ATAPI.
#define  IDE_ATA_IDENTIFY           0xEC  //  Returns ID sector for ATA.
#define  FILE_DEVICE_SCSI           0x0000001b
#define  IOCTL_SCSI_MINIPORT_IDENTIFY  ((FILE_DEVICE_SCSI << 16) + 0x0501)
#define  IOCTL_SCSI_MINIPORT        0x0004D008  //  see NTDDSCSI.H for definition

#define IOCTL_STORAGE_QUERY_PROPERTY   CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define  MAX_IDE_DRIVES  16

#pragma pack(push, 1)

#define  SENDIDLENGTH  sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE

typedef struct _GETVERSIONOUTPARAMS {
    BYTE bVersion;      // Binary driver version.
    BYTE bRevision;     // Binary driver revision.
    BYTE bReserved;     // Not used.
    BYTE bIDEDeviceMap; // Bit map of IDE devices.
    DWORD fCapabilities; // Bit mask of driver capabilities.
    DWORD dwReserved[4]; // For future use.
} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;

typedef struct _IDSECTOR {
    USHORT  wGenConfig;
    USHORT  wNumCyls;
    USHORT  wReserved;
    USHORT  wNumHeads;
    USHORT  wBytesPerTrack;
    USHORT  wBytesPerSector;
    USHORT  wSectorsPerTrack;
    USHORT  wVendorUnique[3];
    CHAR    sSerialNumber[20];
    USHORT  wBufferType;
    USHORT  wBufferSize;
    USHORT  wECCSize;
    CHAR    sFirmwareRev[8];
    CHAR    sModelNumber[40];
    USHORT  wMoreVendorUnique;
    USHORT  wDoubleWordIO;
    USHORT  wCapabilities;
    USHORT  wReserved1;
    USHORT  wPIOTiming;
    USHORT  wDMATiming;
    USHORT  wBS;
    USHORT  wNumCurrentCyls;
    USHORT  wNumCurrentHeads;
    USHORT  wNumCurrentSectorsPerTrack;
    ULONG   ulCurrentSectorCapacity;
    USHORT  wMultSectorStuff;
    ULONG   ulTotalAddressableSectors;
    USHORT  wSingleWordDMA;
    USHORT  wMultiWordDMA;
    BYTE    bReserved[128];
} IDSECTOR, *PIDSECTOR;

typedef struct _SRB_IO_CONTROL {
    ULONG HeaderLength;
    UCHAR Signature[8];
    ULONG Timeout;
    ULONG ControlCode;
    ULONG ReturnCode;
    ULONG Length;
} SRB_IO_CONTROL, *PSRB_IO_CONTROL;

#pragma pack(4)

typedef enum _STORAGE_QUERY_TYPE {
    PropertyStandardQuery = 0,          // Retrieves the descriptor
    PropertyExistsQuery,                // Used to test whether the descriptor is supported
    PropertyMaskQuery,                  // Used to retrieve a mask of writeable fields in the descriptor
    PropertyQueryMaxDefined     // use to validate the value
} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;

typedef enum _STORAGE_PROPERTY_ID {
    StorageDeviceProperty = 0,
    StorageAdapterProperty
} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;

typedef struct _STORAGE_PROPERTY_QUERY {
    STORAGE_PROPERTY_ID PropertyId; // ID of the property being retrieved
    STORAGE_QUERY_TYPE QueryType;   // Flags indicating the type of query being performed
    UCHAR AdditionalParameters[1];  // Space for additional parameters if necessary
    
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;

typedef struct _STORAGE_DEVICE_DESCRIPTOR {
    // Sizeof(STORAGE_DEVICE_DESCRIPTOR)
    ULONG Version;
    // Total size of the descriptor, including the space for additional
    // data and id strings
    ULONG Size;
    // The SCSI-2 device type
    UCHAR DeviceType;
    // The SCSI-2 device type modifier (if any) - this may be zero
    UCHAR DeviceTypeModifier;
    // Flag indicating whether the device's media (if any) is removable.  This
    // field should be ignored for media-less devices
    BOOLEAN RemovableMedia;
    // Flag indicating whether the device can support mulitple outstanding
    // commands.  The actual synchronization in this case is the responsibility
    // of the port driver.
    BOOLEAN CommandQueueing;
    // Byte offset to the zero-terminated ascii string containing the device's
    // vendor id string.  For devices with no such ID this will be zero
    ULONG VendorIdOffset;
    // Byte offset to the zero-terminated ascii string containing the device's
    // product id string.  For devices with no such ID this will be zero
    ULONG ProductIdOffset;
    // Byte offset to the zero-terminated ascii string containing the device's
    // product revision string.  For devices with no such string this will be
    // zero
    ULONG ProductRevisionOffset;
    // Byte offset to the zero-terminated ascii string containing the device's
    // serial number.  For devices with no serial number this will be zero
    ULONG SerialNumberOffset;
    // Contains the bus type (as defined above) of the device.  It should be
    // used to interpret the raw device properties at the end of this structure
    // (if any)
    STORAGE_BUS_TYPE BusType;
    // The number of bytes of bus-specific data which have been appended to
    // this descriptor
    ULONG RawPropertiesLength;
    // Place holder for the first byte of the bus specific property data
    UCHAR RawDeviceProperties[1];
    
} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;

typedef struct _MEDIA_SERAL_NUMBER_DATA {
    ULONG  SerialNumberLength;
    ULONG  Result;
    ULONG  Reserved[2];
    UCHAR  SerialNumberData[1];
} MEDIA_SERIAL_NUMBER_DATA, *PMEDIA_SERIAL_NUMBER_DATA;

#pragma pack(pop)

class CGetHardwareInfo {
  public:
    CGetHardwareInfo();
    virtual ~CGetHardwareInfo();
    
    static void GetIdeDiskSerialNumber(char pcDest[24], const char *strUserName);
    
  private:
    static void WinNTHDSerialNumAsPhysicalRead(char pcDest[24]);
    static void WinNTHDSerialNumAsScsiRead(char pcDest[24]);
    static void WinNTHDSerialNumWithZeroRights(char pcDest[24]);
    static char *flipAndCodeBytes (char *str);
    
    static void ReadVolumnSerialNum(char pcDest[24], const char *strUserName);
};
NAMESPACE_HARDWARE_END
#endif // !defined(AFX_GETHWINFO_H__3ABD86B7_D2D2_43EB_B89D_582D73A89BF8__INCLUDED_)
